﻿
#include <iostream>
#include <algorithm>
#include <vector>
#include <math.h>
#include <memory.h>
using namespace std;


/*

https://www.papamelon.com/problem/363


这是一个图论问题。
在平面上给出 N 个点，每个点都有 x,y 坐标。
再给出 M 条边，连接这些点。边的长度等于两点间的直线距离。
现在我们要删除一些边，使得整个图没有环，同时保证任意两个点是连通的。
删除一条边的代价等于边的长度，现在让我们求删除后满足要求的最小代价。

输入
第一行两个整数 N(1≤N≤10000),M(1≤M≤2∗10^5)，表示点的数量和边的数量
接下来 N 行，每行两个整数x,y(−10000≤x,y≤10000)，表示点的坐标
接下来 M 行，每行两个整数p,q(1≤p,q≤N)，表示第 p 和 q 个点之间有边，边的长度等于两点间的直线距离，不会包含重复的p,q 对
输出
一行，一个浮点数，表示最小代价
和正确答案的误差不能超过 0.001
提示
本题采用 special judge，只要答案满足误差要求即可
提交详情中，标准答案一栏为空，不予显示
样例 1
输入
3 3
0 0
3 0
0 4
1 2
2 3
3 1
输出
3.000
*/

const int INF = 0x3f3f3f3f;
const int N = 10010;
const int M = 200010;

pair<int, int> points[N];
int p[N];

struct Edge
{
	int x, y;
	double w;

	bool operator< (const Edge &W)const
	{
		return w < W.w;
	}
}edges[M];

int n, m;


double GetLen(int a, int b) {
	int x1 = points[a].first; int y1 = points[a].second;
	int x2 = points[b].first; int y2 = points[b].second;

	double ret = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
	return ret;
}



int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

double kruskal()
{
	sort(edges, edges + m);

	for (int i = 1; i <= n; i++) p[i] = i;    // 初始化并查集

	double res = 0.0;

	int selArr[M]; memset(selArr, 0, sizeof selArr);
	int cnt = 0;
	for (int i = 0; i < m; i++)
	{
		int a = edges[i].x, b = edges[i].y; double w = edges[i].w;

		a = find(a), b = find(b);
		if (a != b)
		{
			p[a] = b;
			selArr[i] = 1;
			cnt++;
		}
	}

	for (int i = 0; i < m; i++) {
		if (selArr[i] == 1) continue;
		res += -edges[i].w;
	}

	return res;
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		int a, b; cin >> a >> b;
		points[i] = { a,b };
	}
	for (int i = 0; i < m; i++) {
		int p, q;
		cin >> p >> q;
		double len = -GetLen(p, q);
		edges[i] = { p,q,len };
	}

	//cout << kruskal() <<endl;
	printf("%.3f\n", kruskal());

	return 0;
}
